{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a name=\"top\"></a><img src=\"source/SpinalHDL.png\" alt=\"SpinalHDL based on Scala\" style=\"width:320px;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Before running Spinal HDL code, be sure to load SpinalHDL Libraries  \n",
    "**Note** : This may be a little slow when the first time load, please wait a moment to download Lib from remote."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val path = System.getProperty(\"user.dir\") + \"/source/load-spinal.sc\"\n",
    "interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Implicit\n",
    "### Example "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Rational(val n: Int, val d:Int) {\n",
    "  require(d != 0)\n",
    "  override def toString = n + \"/\" + d\n",
    "  def +(x: Rational): Rational = new Rational(this.n*x.d + x.n*this.d, this.d * x.d)\n",
    "  def +(x: Int): Rational = new Rational(this.n + x*this.d, this.d)\n",
    "}\n",
    "val a = new Rational(2,3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val b = new Rational(1,4)\n",
    "val r0 = a + b\n",
    "val r1 = a + 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val r2 = 2 + a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This cause an error, you can find `Int 2` have not method `+(x: Rtional)`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "we have 2 way to implement that \n",
    "\n",
    "**way1 translate Int to Rational**  \n",
    "There's nothing to discuss about explicit transformation, This is what we do in general languages\n",
    "```\n",
    "val r2 = new Ration(2,1) + a\n",
    "```\n",
    "If there is a large number of such operations, it is obviously very cumbersome. so an implicit transform is very elegant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "implicit def transInt2Rational(x: Int) = new Rational(x,1)\n",
    "val r2 = 2 + a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**way2 add a method of `+(x: Rational)` to Int**  \n",
    "\n",
    "We can't modify Scala's source code to add methods to Int.  \n",
    "\n",
    "But Scala's fascinating implicit transformation allows us to add methods to a type without modifying the source code, as if the type itself had its own methods"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "implicit class expandInt(t: Int){\n",
    "    def +(x: Rational): Rational = new Rational(t,1) + x\n",
    "}\n",
    "val r2 = 2 + a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1 Implicit Transform\n",
    "**transform only when needed, else do nothing**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "case class Euro(value: Double)\n",
    "case class Dollar(value: Double)\n",
    "\n",
    "object Dollar{\n",
    "    implicit def dollarToEuro(x: Dollar): Euro = Euro(x.value*0.75)\n",
    "}\n",
    "\n",
    "val a = Dollar(12)\n",
    "val b: Euro = Dollar(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val a = 3.001 * 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val b = 2 * 3.0001 \n",
    "\n",
    "object Int {\n",
    " def *(x :Int): Int = this * x\n",
    " def *(x :Double): Double = Double(this) * x\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val x: Double = 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val x:Int = 3.000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val x: Int = 3.001.toInt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2 implicit Extend\n",
    "**Silently enhance the Class without changing anything of the original Class **\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3 implicit Parameter\n",
    "**Implicitly define a parameter and pass it in implicitly, which is transparent to users**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "object Test{\n",
    "    def show(implicit h: Euro) = {\n",
    "        println(h.value)\n",
    "    }\n",
    "}\n",
    "implicit val h = Euro(12)\n",
    "Test.show"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 implicit Generator（Cooperation of implicit transform and parameter）\n",
    "\n",
    "**purpose**：generate one if not exist else do nothing \n",
    "**difference**：\"implicit transform\" with parameter，*implicti generator*: without parameter\n",
    "\n",
    "*if there have no explicit parameter , Implicit generator are triggered, and there will get on generator object*\n",
    "```scala\n",
    "def hello(implicit h: ClassName) = {}\n",
    "...\n",
    "Test.hello //when the have no parameter , implicit generator one\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "case class ClassName(name: String)\n",
    "object ClassName {\n",
    "  //generator on when needed \n",
    "  implicit def genWhenNeed: ClassName = ClassName(\"Example\")\n",
    "}\n",
    "object Test{\n",
    "    def hello(implicit h: ClassName) = {\n",
    "        println(h.name)\n",
    "    }\n",
    "}\n",
    "Test.hello(ClassName(\"jack\"))\n",
    "Test.hello"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition to the induction triggered implicit generate\n",
    "\n",
    "**You can also manually get an implicit object by`implicitly[]`**，attention it's`[]`， not`()`\n",
    "\n",
    "```scala\n",
    "val b = implicitly[ClassName]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val b = implicitly[ClassName]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5 implicit generator and Macro\n",
    "\n",
    "This provides a way to deal with compilers\n",
    "\n",
    "- Way 1\n",
    "```scala \n",
    "def getLineNumber(implicit line: LineNumber) ={\n",
    "      println(\"add at ${line}\"\n",
    "      line\n",
    "}\n",
    "val s = getLineNumber\n",
    "```\n",
    "\n",
    "- Way2\n",
    "```scala\n",
    "val s = implicitly[LineNumber]\n",
    "```\n",
    "\n",
    "\n",
    "(*Note: Scala macro have some problems in jupyter env. Please compile and run the instance in SBT environment*)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//Gets the current number of lines of code\n",
    "import language.experimental.macros\n",
    "import reflect.macros.blackbox.Context\n",
    "\n",
    "case class LineNumber(no: Int)\n",
    "\n",
    "object LineNumber {\n",
    "  implicit def genWhenNeed: LineNumber = macro Macros.lineNumberImpl\n",
    "}\n",
    "\n",
    "object Macros{\n",
    "  def lineNumberImpl(c: Context): c.Expr[LineNumber] = {\n",
    "    import c.universe._\n",
    "    val lineNumber = c.enclosingPosition.line\n",
    "    c.Expr[LineNumber](q\"\"\"${c.prefix}($lineNumber)\"\"\")\n",
    "  }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//Get variable name\n",
    "import language.experimental.macros\n",
    "import reflect.macros.blackbox.Context\n",
    "\n",
    "case class SymbolName(name: String)\n",
    "case class ClassName(name: String)\n",
    "\n",
    "object SymbolName{\n",
    "  implicit def genWhenNeed: SymbolName = macro Macros.symbolNameImpl\n",
    "}\n",
    " \n",
    "\n",
    "object Macros{\n",
    "  def symbolNameImpl(c: Context): c.Expr[SymbolName] = {\n",
    "    import c.universe._\n",
    "    val symbolName = c.internal.enclosingOwner.name.decodedName.toString.trim\n",
    "    c.Expr[SymbolName](q\"\"\"${c.prefix}($symbolName)\"\"\")\n",
    "  }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creat a Complex from Zero\n",
    "```scala\n",
    "val a = 2 + 3.2*j \n",
    "val b = 3.001 -7*j\n",
    "val c = a * b\n",
    "println(c)\n",
    "28.402 - 4.397j\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import scala.math._\n",
    "case class Complex(re: Double, im: Double) {\n",
    "    def +(x: Complex): Complex = Complex(re + x.re, im + x.im)\n",
    "    def -(x: Complex): Complex = Complex(re - x.re, im - x.im)\n",
    "    def *(x: Double):  Complex = Complex(re * x, im * x)\n",
    "    def *(x: Complex): Complex = Complex(re * x.re - im * x.im, re * x.im + im * x.re)\n",
    "    def /(x: Double):  Complex = Complex(re / x, im / x)\n",
    " \n",
    "    override def toString(): String = {\n",
    "        val a = \"%1.3f\".format(re)\n",
    "        val b = \"%1.3f\".format(abs(im))\n",
    "        (a,b) match {\n",
    "            case (_, \"0.000\") => a\n",
    "            case (\"0.000\", _) => b + \"j\"\n",
    "            case (_, _) if im > 0 => a + \" + \" + b + \"j\"\n",
    "            case (_, _) => a + \" - \" + b + \"j\"\n",
    "        }\n",
    "    }\n",
    "} "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait jbase\n",
    "object j extends jbase\n",
    "case class image(value: Double)\n",
    "implicit class compleInt(x: Int) {\n",
    "    def *(y: jbase) = image(x toDouble)\n",
    "}\n",
    "implicit class compleDouble(x: Double) {\n",
    "    def *(y: jbase) = image(x)\n",
    "}\n",
    "implicit class DoubleExpand(x: Double) {\n",
    "    def +(that: image) = Complex(x,that.value)\n",
    "    def -(that: image) = Complex(x,-that.value)\n",
    "}\n",
    "implicit class intExpand(x: Int) {\n",
    "    def +(that: image) = Complex(x toDouble,that.value)\n",
    "    def -(that: image) = Complex(x toDouble,-that.value)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val a = 2 + 3.2*j \n",
    "val b = 3.001 -7*j\n",
    "val c = a * b\n",
    "println(c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val N = 64\n",
    "(0 to N/4).map(2*Pi*_/N).map(t => cos(t)+sin(t)*j )"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Scala",
   "language": "scala",
   "name": "scala"
  },
  "language_info": {
   "codemirror_mode": "text/x-scala",
   "file_extension": ".scala",
   "mimetype": "text/x-scala",
   "name": "scala",
   "nbconvert_exporter": "script",
   "version": "2.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
